#ifndef __INCdllLibh
#define __INCdllLibh

/* type definitions */

typedef struct dlnode /* Node of a linked list. */
{
    struct dlnode *next;     /* Points at the next node in the list */
    struct dlnode *previous; /* Points at the previous node in the list */
} DL_NODE;

typedef struct /* Header for a linked list. */
{
    DL_NODE *head; /* header of list */
    DL_NODE *tail; /* tail of list */
} DL_LIST;

#define DLL_INIT(list)                    \
    {                                     \
        ((DL_LIST *)(list))->head = NULL; \
        ((DL_LIST *)(list))->tail = NULL; \
    }

#define DLL_FIRST(pList) \
    ((((DL_LIST *)(pList))->head))

#define DLL_LAST(pList) \
    ((((DL_LIST *)(pList))->tail))

#define DLL_NEXT(pNode) \
    ((((DL_NODE *)(pNode))->next))

#define DLL_PREVIOUS(pNode) \
    ((((DL_NODE *)(pNode))->previous))

#define DLL_EMPTY(pList) \
    ((((DL_LIST *)pList)->head == NULL))

#define DLL_INSERT(list, previousNode, node)                       \
    {                                                              \
        DL_NODE *temp;                                             \
        if ((previousNode) == NULL)                                \
        {                                                          \
            temp = ((DL_LIST *)(list))->head;                      \
            ((DL_LIST *)(list))->head = (DL_NODE *)(node);         \
        }                                                          \
        else                                                       \
        {                                                          \
            temp = ((DL_NODE *)(previousNode))->next;              \
            ((DL_NODE *)(previousNode))->next = (DL_NODE *)(node); \
        }                                                          \
        if (temp == NULL)                                          \
        {                                                          \
            ((DL_LIST *)(list))->tail = (DL_NODE *)(node);         \
        }                                                          \
        else                                                       \
        {                                                          \
            temp->previous = (DL_NODE *)(node);                    \
        }                                                          \
        ((DL_NODE *)(node))->next = temp;                          \
        ((DL_NODE *)(node))->previous = (DL_NODE *)(previousNode); \
    }

#define DLL_ADD(list, node)                   \
    {                                         \
        DL_NODE *listTail = (list)->tail;     \
        DLL_INSERT((list), listTail, (node)); \
    }

#define DLL_REMOVE(list, node)                                                   \
    {                                                                            \
        if (((DL_NODE *)(node))->previous == NULL)                               \
        {                                                                        \
            ((DL_LIST *)(list))->head = ((DL_NODE *)(node))->next;               \
        }                                                                        \
        else                                                                     \
        {                                                                        \
            ((DL_NODE *)(node))->previous->next = ((DL_NODE *)(node))->next;     \
        }                                                                        \
        if (((DL_NODE *)(node))->next == NULL)                                   \
        {                                                                        \
            ((DL_LIST *)(list))->tail = ((DL_NODE *)(node))->previous;           \
        }                                                                        \
        else                                                                     \
        {                                                                        \
            ((DL_NODE *)(node))->next->previous = ((DL_NODE *)(node))->previous; \
        }                                                                        \
    }

#define DLL_GET(list, node)                                        \
    {                                                              \
        (node) = (void *)((DL_LIST *)(list))->head;                \
        if ((node) != NULL)                                        \
        {                                                          \
            ((DL_LIST *)(list))->head = ((DL_NODE *)(node))->next; \
            if (((DL_NODE *)(node))->next == NULL)                 \
            {                                                      \
                ((DL_LIST *)(list))->tail = NULL;                  \
            }                                                      \
            else                                                   \
            {                                                      \
                ((DL_NODE *)(node))->next->previous = NULL;        \
            }                                                      \
        }                                                          \
    }
#endif /* __INCdllLibh */